/*
 Copyright (c) 2013 MeherTJ G. All rights reserved.
 License: LGPL for personnal study or free software.
 */

#include "./stb/stb_image_write.h"
#include "./stb/stb_image_load.h"

#include "zen_image_coder.h"
#include "zen_file.h"
#include "zen_log.h"
#include "zen_endian.h"
#include "zen_exception.h"

namespace Zen
{
    static void WriteFunc(void* context, void* value, int size)
    {
        auto& v = *(std::vector<uint8_t>*)context;
        v.insert(v.end(), (uint8_t*)value, (uint8_t*)value + size);
    }

    ImageJPGEncoder::ImageJPGEncoder(float quality)
    {
        mQuality = quality;
    }

    std::vector<uint8_t> ImageJPGEncoder::encode(Image const& image)
    {
        std::vector<uint8_t> v;
        int w = (int)image.Width();
        int h = (int)image.Height();
        int comp = (int)image.PixelType();
        int q = (int)(mQuality * 100.f);
        if (stbi_write_jpg_to_func(&WriteFunc, &v, w, h, comp, image.Data(), q)) return v;
        return {};
    }
    std::vector<uint8_t> ImagePNGEncoder::encode(Image const& image)
    {
        std::vector<uint8_t> v;
        int w = (int)image.Width();
        int h = (int)image.Height();
        int comp = (int)image.PixelType();
        if (stbi_write_png_to_func(&WriteFunc, &v, w, h, comp, image.Data(), 0)) return v;
        return {};
    }
    std::shared_ptr<Image> ImageSTBDecoder::decode(const std::vector<uint8_t>& value)
    {
        int x = 0, y = 0, comp = 0;
        auto p = stbi_load_from_memory(value.data(), (int)value.size(), &x, &y, &comp, 0);

        if (!p)
        {
            Zen::LogD("load image failed");
            return nullptr;
        }
        std::shared_ptr<stbi_uc> r(p, [](stbi_uc* p) { free(p); });

        if (comp > 0 && comp <= 4)
        {
            return Image::GenerateWithData((EPixel)comp, (size_t)x, (size_t)y, r.get());
        }
        return nullptr;
    }
    std::vector<uint8_t> ImageTGAEncoder::encode(Image const& image)
    {
        std::vector<uint8_t> v;
        int w = (int)image.Width();
        int h = (int)image.Height();
        int comp = (int)image.PixelType();
        if (stbi_write_tga_to_func(&WriteFunc, &v, w, h, comp, image.Data())) return v;
        return {};
    }
    std::vector<uint8_t> ImageBMPEncoder::encode(Image const& image)
    {
        std::vector<uint8_t> v;
        int w = (int)image.Width();
        int h = (int)image.Height();
        int comp = (int)image.PixelType();
        if (stbi_write_bmp_to_func(&WriteFunc, &v, w, h, comp, image.Data())) return v;
        return {};
    }
} // namespace Zen
